/*
 * Copyright (C) 2025 ameise <ameise.wang@gmail.com> - All Rights Reserved
 *
 * This file is part of e3ds.
 *
 * e3ds is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * e3ds is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with e3ds. If not, see <https://www.gnu.org/licenses/>.
 */

package rtree

func newRect(min, max Point) rect {
	p := rect{}
	p.set(min, max)
	return p
}

type rect struct {
	min  Point
	max  Point
	area float64
}

func (ts *rect) copy(b *rect) {
	ts.min = b.min
	ts.max = b.max
	ts.area = b.area
}

func (ts *rect) clone() rect {
	return rect{ts.min, ts.max, ts.area}
}

func (ts *rect) clean() {
	ts.min.X = 0
	ts.max.X = 0
	ts.min.Y = 0
	ts.max.Y = 0
	ts.area = 0
}

func (ts *rect) set(min, max Point) {
	ts.min = min
	ts.max = max
	ts.calcArea()
}

func (ts *rect) calcArea() {
	ts.area = float64((ts.max.Y - ts.min.Y) * (ts.max.X - ts.min.X))
}

func (ts *rect) isOverlap(b *rect, withAdj bool) bool {
	if withAdj {
		if b.min.X > ts.max.X || b.max.X < ts.min.X {
			return false
		}
		if b.min.Y > ts.max.Y || b.max.Y < ts.min.Y {
			return false
		}
	} else {
		if b.min.X >= ts.max.X || b.max.X <= ts.min.X {
			return false
		}
		if b.min.Y >= ts.max.Y || b.max.Y <= ts.min.Y {
			return false
		}
	}
	return true
}

func (ts *rect) merge(args ...*rect) bool {
	if len(args) == 0 {
		return false
	}
	grown := false
	for _, arg := range args {
		if arg.min.X < ts.min.X {
			ts.min.X = arg.min.X
			grown = true
		}
		if arg.min.Y < ts.min.Y {
			ts.min.Y = arg.min.Y
			grown = true
		}
		if arg.max.X > ts.max.X {
			ts.max.X = arg.max.X
			grown = true
		}
		if arg.max.Y > ts.max.Y {
			ts.max.Y = arg.max.Y
			grown = true
		}
	}
	if grown {
		ts.calcArea()
	}
	return grown
}

func (ts *rect) checkMergeRect(b *rect) rect {
	nr := ts.clone()
	nr.merge(b)
	return nr
}

func (ts *rect) onEdge(b *rect) bool {
	if ts.min.X == b.min.X || ts.max.X == b.max.X {
		return true
	}
	if ts.min.Y == b.min.Y || ts.max.Y == b.max.Y {
		return true
	}
	return false
}
